package httptools;

import com.lidroid.xutils.HttpUtils;
import android.text.TextUtils;
import android.util.Log;

import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.*;
import com.lidroid.xutils.http.callback.HttpRedirectHandler;
import com.lidroid.xutils.http.callback.RequestCallBack;
import com.lidroid.xutils.http.client.DefaultSSLSocketFactory;
import com.lidroid.xutils.http.client.HttpRequest;
import com.lidroid.xutils.http.client.RetryHandler;
import com.lidroid.xutils.http.client.entity.GZipDecompressingEntity;
import com.lidroid.xutils.task.PriorityExecutor;
import com.lidroid.xutils.util.OtherUtils;
import org.apache.http.*;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;

import java.io.File;
import java.io.IOException;

/**
 * * @author 作者 陈修园:
 * 
 * @date 创建时间：2015-5-25 下午11:03:41
 * @version 1.0
 * @parameter
 * @since
 * @return
 */
public class HttpsUtils extends HttpUtils {

	public final static HttpCache sHttpCache = new HttpCache();

	private String responseTextCharset = HTTP.UTF_8;

	private long currentRequestExpiry = HttpCache.getDefaultExpiryTime();

	private final static int DEFAULT_CONN_TIMEOUT = 1000 * 15; // 15s

	private final static int DEFAULT_RETRY_TIMES = 3;

	private static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
	private static final String ENCODING_GZIP = "gzip";

	private final static int DEFAULT_POOL_SIZE = 3;
	private final static PriorityExecutor EXECUTOR = new PriorityExecutor(
			DEFAULT_POOL_SIZE);

	private final DefaultHttpClient httpClient;
	private final HttpContext httpContext = new BasicHttpContext();

	private HttpRedirectHandler httpRedirectHandler;

	public HttpsUtils() {
		
		this(HttpsUtils.DEFAULT_CONN_TIMEOUT, null);
		Log.v("1", "1");
	}

	public HttpsUtils(int connTimeout) {
		this(connTimeout, null);
	}

	public HttpsUtils(String userAgent) {
		this(HttpsUtils.DEFAULT_CONN_TIMEOUT, userAgent);
	}

	public HttpsUtils(int connTimeout, String userAgent) {
		HttpParams params = new BasicHttpParams();

		ConnManagerParams.setTimeout(params, connTimeout);
		HttpConnectionParams.setSoTimeout(params, connTimeout);
		HttpConnectionParams.setConnectionTimeout(params, connTimeout);

		if (TextUtils.isEmpty(userAgent)) {
			userAgent = OtherUtils.getUserAgent(null);
		}
		HttpProtocolParams.setUserAgent(params, userAgent);

		ConnManagerParams.setMaxConnectionsPerRoute(params,
				new ConnPerRouteBean(10));
		ConnManagerParams.setMaxTotalConnections(params, 10);

		HttpConnectionParams.setTcpNoDelay(params, true);
		HttpConnectionParams.setSocketBufferSize(params, 1024 * 8);
		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);

		SchemeRegistry schemeRegistry = new SchemeRegistry();
		schemeRegistry.register(new Scheme("http", PlainSocketFactory
				.getSocketFactory(), 80));
		schemeRegistry.register(new Scheme("https", DefaultSSLSocketFactory
				.getSocketFactory(), 443));

		httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager(
				params, schemeRegistry), params);

		httpClient.setHttpRequestRetryHandler(new RetryHandler(
				DEFAULT_RETRY_TIMES));

		httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
			@Override
			public void process(org.apache.http.HttpRequest httpRequest,
					HttpContext httpContext)
					throws org.apache.http.HttpException, IOException {
				if (!httpRequest.containsHeader(HEADER_ACCEPT_ENCODING)) {
					httpRequest
							.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
				}
			}
		});

		httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
			@Override
			public void process(HttpResponse response, HttpContext httpContext)
					throws org.apache.http.HttpException, IOException {
				final HttpEntity entity = response.getEntity();
				if (entity == null) {
					return;
				}
				final Header encoding = entity.getContentEncoding();
				if (encoding != null) {
					for (HeaderElement element : encoding.getElements()) {
						if (element.getName().equalsIgnoreCase("gzip")) {
							response.setEntity(new GZipDecompressingEntity(
									response.getEntity()));
							return;
						}
					}
				}
			}
		});
	}

	// ************************************ default settings & fields
	// ****************************

	public HttpClient getHttpClient() {
		return this.httpClient;
	}

	// ***************************************** config
	// *******************************************

	public HttpsUtils configResponseTextCharset(String charSet) {
		if (!TextUtils.isEmpty(charSet)) {
			this.responseTextCharset = charSet;
		}
		return this;
	}

	public HttpsUtils configHttpRedirectHandler(
			HttpRedirectHandler httpRedirectHandler) {
		this.httpRedirectHandler = httpRedirectHandler;
		return this;
	}

	public HttpsUtils configHttpCacheSize(int httpCacheSize) {
		sHttpCache.setCacheSize(httpCacheSize);
		return this;
	}

	public HttpsUtils configDefaultHttpCacheExpiry(long defaultExpiry) {
		HttpCache.setDefaultExpiryTime(defaultExpiry);
		currentRequestExpiry = HttpCache.getDefaultExpiryTime();
		return this;
	}

	public HttpsUtils configCurrentHttpCacheExpiry(long currRequestExpiry) {
		this.currentRequestExpiry = currRequestExpiry;
		return this;
	}

	public HttpsUtils configCookieStore(CookieStore cookieStore) {
		httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
		return this;
	}

	public HttpsUtils configUserAgent(String userAgent) {
		HttpProtocolParams.setUserAgent(this.httpClient.getParams(), userAgent);
		return this;
	}

	public HttpsUtils configTimeout(int timeout) {
		final HttpParams httpParams = this.httpClient.getParams();
		ConnManagerParams.setTimeout(httpParams, timeout);
		HttpConnectionParams.setConnectionTimeout(httpParams, timeout);
		return this;
	}

	public HttpsUtils configSoTimeout(int timeout) {
		final HttpParams httpParams = this.httpClient.getParams();
		HttpConnectionParams.setSoTimeout(httpParams, timeout);
		return this;
	}

	public HttpsUtils configRegisterScheme(Scheme scheme) {
		this.httpClient.getConnectionManager().getSchemeRegistry()
				.register(scheme);
		return this;
	}

	public HttpsUtils configSSLSocketFactory(SSLSocketFactory sslSocketFactory) {
		Scheme scheme = new Scheme("https", sslSocketFactory, 443);
		this.httpClient.getConnectionManager().getSchemeRegistry()
				.register(scheme);
		return this;
	}

	public HttpsUtils configRequestRetryCount(int count) {
		this.httpClient.setHttpRequestRetryHandler(new RetryHandler(count));
		return this;
	}

	public HttpsUtils configRequestThreadPoolSize(int threadPoolSize) {
		HttpsUtils.EXECUTOR.setPoolSize(threadPoolSize);
		return this;
	}

	// ***************************************** send request
	// *******************************************

	public <T> HttpHandler<T> send(HttpRequest.HttpMethod method, String url,
			RequestCallBack<T> callBack) {
		return send(method, url, null, callBack);
	}

	public <T> HttpHandler<T> send(HttpRequest.HttpMethod method, String url,
			RequestParams params, RequestCallBack<T> callBack) {
		if (url == null)
			throw new IllegalArgumentException("url may not be null");

		HttpRequest request = new HttpRequest(method, url);
		return sendRequest(request, params, callBack);
	}

	public ResponseStream sendSync(HttpRequest.HttpMethod method, String url)
			throws HttpException {
		return sendSync(method, url, null);
	}

	public ResponseStream sendSync(HttpRequest.HttpMethod method, String url,
			RequestParams params) throws HttpException {
		if (url == null)
			throw new IllegalArgumentException("url may not be null");

		HttpRequest request = new HttpRequest(method, url);
		return sendSyncRequest(request, params);
	}

	// ***************************************** download
	// *******************************************

	public HttpHandler<File> download(String url, String target,
			RequestCallBack<File> callback) {
		return download(HttpRequest.HttpMethod.GET, url, target, null, false,
				false, callback);
	}

	public HttpHandler<File> download(String url, String target,
			boolean autoResume, RequestCallBack<File> callback) {
		return download(HttpRequest.HttpMethod.GET, url, target, null,
				autoResume, false, callback);
	}

	public HttpHandler<File> download(String url, String target,
			boolean autoResume, boolean autoRename,
			RequestCallBack<File> callback) {
		return download(HttpRequest.HttpMethod.GET, url, target, null,
				autoResume, autoRename, callback);
	}

	public HttpHandler<File> download(String url, String target,
			RequestParams params, RequestCallBack<File> callback) {
		return download(HttpRequest.HttpMethod.GET, url, target, params, false,
				false, callback);
	}

	public HttpHandler<File> download(String url, String target,
			RequestParams params, boolean autoResume,
			RequestCallBack<File> callback) {
		return download(HttpRequest.HttpMethod.GET, url, target, params,
				autoResume, false, callback);
	}

	public HttpHandler<File> download(String url, String target,
			RequestParams params, boolean autoResume, boolean autoRename,
			RequestCallBack<File> callback) {
		return download(HttpRequest.HttpMethod.GET, url, target, params,
				autoResume, autoRename, callback);
	}

	public HttpHandler<File> download(HttpRequest.HttpMethod method,
			String url, String target, RequestParams params,
			RequestCallBack<File> callback) {
		return download(method, url, target, params, false, false, callback);
	}

	public HttpHandler<File> download(HttpRequest.HttpMethod method,
			String url, String target, RequestParams params,
			boolean autoResume, RequestCallBack<File> callback) {
		return download(method, url, target, params, autoResume, false,
				callback);
	}

	public HttpHandler<File> download(HttpRequest.HttpMethod method,
			String url, String target, RequestParams params,
			boolean autoResume, boolean autoRename,
			RequestCallBack<File> callback) {

		if (url == null)
			throw new IllegalArgumentException("url may not be null");
		if (target == null)
			throw new IllegalArgumentException("target may not be null");

		HttpRequest request = new HttpRequest(method, url);

		HttpHandler<File> handler = new HttpHandler<File>(httpClient,
				httpContext, responseTextCharset, callback);

		handler.setExpiry(currentRequestExpiry);
		handler.setHttpRedirectHandler(httpRedirectHandler);

		if (params != null) {
			request.setRequestParams(params, handler);
			handler.setPriority(params.getPriority());
		}
		handler.executeOnExecutor(EXECUTOR, request, target, autoResume,
				autoRename);
		return handler;
	}

	// //////////////////////////////////////////////////////////////////////////////////////////////
	private <T> HttpHandler<T> sendRequest(HttpRequest request,
			RequestParams params, RequestCallBack<T> callBack) {

		HttpHandler<T> handler = new HttpHandler<T>(httpClient, httpContext,
				responseTextCharset, callBack);

		handler.setExpiry(currentRequestExpiry);
		handler.setHttpRedirectHandler(httpRedirectHandler);
		request.setRequestParams(params, handler);

		if (params != null) {
			handler.setPriority(params.getPriority());
		}
		handler.executeOnExecutor(EXECUTOR, request);
		return handler;
	}

	private ResponseStream sendSyncRequest(HttpRequest request,
			RequestParams params) throws HttpException {

		SyncHttpHandler handler = new SyncHttpHandler(httpClient, httpContext,
				responseTextCharset);

		handler.setExpiry(currentRequestExpiry);
		handler.setHttpRedirectHandler(httpRedirectHandler);
		request.setRequestParams(params);

		return handler.sendRequest(request);
	}

}
